#include "liomusic.h"

#pragma comment( lib, "Winmm.lib" )					// Search For Winmm.lib While Linking

namespace Lio {

BOOL playSound(CSTR filename, BOOL repeat)
{
	DWORD flags=SND_ASYNC|SND_FILENAME;
	if(repeat)
		flags|=SND_LOOP;
	return PlaySound(filename,NULL,flags);
}
void stopSound()
{
	PlaySound(NULL,NULL,0);
}

CSTR MidiPlayer::getErrorStr()
{
	ClearMemory(errorStr,sizeof(errorStr));
	mciGetErrorString(error,errorStr,MCI_ERROR_STR);
	return errorStr;
}
void MidiPlayer::setWindow(HWND hWnd)
{
	wndNotify=(DWORD_PTR)hWnd;
	mciOpenParms.dwCallback=wndNotify;
	mciPlayParms.dwCallback=wndNotify;
	mciGenParms.dwCallback=wndNotify;
	mciSetParms.dwCallback=wndNotify;
}
BOOL MidiPlayer::notify(LPARAM lParam, WPARAM wParam)
{
	if(wDeviceID!=(UINT)lParam)
		return FALSE;
	{
		msg++;
		status=(WORD)wParam;
		if(status&MCI_NOTIFY_SUCCESSFUL)
		{
			switch(state)
			{
			case MIDI_STATE_CLOSE:
				state=MIDI_STATE_CLOSED;
				break;
			case MIDI_STATE_OPEN:
				state=MIDI_STATE_OPENED;
				break;
			case MIDI_STATE_PLAY:
				state=MIDI_STATE_PLAYED;
				break;
			case MIDI_STATE_PAUSE:
				state=MIDI_STATE_PAUSED;
				break;
			default:
				return FALSE;
			}
		}
	}
	return TRUE;
}
void MidiPlayer::reset()
{
	commands.destroy();
	state=MIDI_STATE_CLOSED;
	status=MCI_NOTIFY_SUCCESSFUL;
	wDeviceID=MIDI_MAPPER;
}
BOOL MidiPlayer::send(WORD id, CSTR str, DWORD val)
{
	if(!running_thread)
		return FALSE;
	Lock lock(&cs);
	MidiCommand *comm=commands.add();
	if(!comm)
		return FALSE;
	comm->id=id;
	comm->str=str;
	comm->val=val;
	command_available.Signal();
	return TRUE;
}
DWORD MidiPlayer::run(const ThreadInfo *ti)
{
	if(ti != &this->ti)
		return 0;

	MidiCommand *comm;

	if(running_thread)
		return 1;

	running_thread=GetCurrentThread();

	while(running_thread)
	{
		while(!commands.first)
			command_available.Wait();

		comm=&commands.first->value;

		switch(comm->id)
		{
		case MIDI_COMM_PLAY:
			if(	wDeviceID!=MIDI_MAPPER&&state!=MIDI_STATE_CLOSED&&
				!(error = mciSendCommand(wDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD_PTR)&mciPlayParms)))
				state=MIDI_STATE_PLAY;
			break;
		case MIDI_COMM_OPEN:
			mciOpenParms.lpstrElementName = comm->str;
			if(!(error = mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT|MCI_NOTIFY,(DWORD_PTR)&mciOpenParms)))
			{
				wDeviceID = mciOpenParms.wDeviceID;
				state=MIDI_STATE_OPEN;
			}
			break;
		case MIDI_COMM_CLOSE:
			if(	wDeviceID!=MIDI_MAPPER&&state!=MIDI_STATE_CLOSED&&
				!(error = mciSendCommand(wDeviceID,MCI_CLOSE,MCI_NOTIFY,(DWORD_PTR)&mciGenParms)))
				state=MIDI_STATE_CLOSE;
			break;
		case MIDI_COMM_PAUSE:
			if(	wDeviceID!=MIDI_MAPPER&&state!=MIDI_STATE_CLOSED&&
				!(error = mciSendCommand(wDeviceID,MCI_PAUSE,MCI_NOTIFY,(DWORD_PTR)&mciGenParms)))
				state=MIDI_STATE_PAUSE;
			break;
		case MIDI_COMM_SET_TEMPO:
			mciSetParms.dwTempo=comm->val;
			if(	wDeviceID!=MIDI_MAPPER&&
				!(error = mciSendCommand(wDeviceID,MCI_SET,MCI_SEQ_SET_TEMPO,(DWORD_PTR)&mciSetParms)))
				tempo=comm->val;
			break;
		case MIDI_COMM_GET_TEMPO:
			mciStatParms.dwItem=MCI_SEQ_STATUS_TEMPO;
			if(	wDeviceID!=MIDI_MAPPER&&
				!(error = mciSendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD_PTR)&mciStatParms)))
				tempo=(DWORD)mciStatParms.dwReturn;
			break;
		case MIDI_COMM_GET_DIV:
			mciStatParms.dwItem=MCI_SEQ_STATUS_DIVTYPE;
			if(	wDeviceID!=MIDI_MAPPER&&
				!(error = mciSendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD_PTR)&mciStatParms)))
				div=(DWORD)mciStatParms.dwReturn;
			break;
		}
		{
			Lock lock(&cs);
			commands.remove(0);
		}
		Sleep(0);
	}
	return 0;
}

}; // namespace Lio